package com.jffccloud.provider.api.disruptor;

import com.lmax.disruptor.*;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.ParameterizedType;
import java.util.concurrent.Executors;

/**
 * @author wwwang
 * 功能说明：disruptor 基类
 * E 是事件
 * A 是参数
 */
@Slf4j
public abstract class AbstractDisruptorService<E,T extends EventTranslatorVararg,F extends EventFactory,A>{

    @Autowired
    public EventHandler<E>[] eventHandlers;

    /**
     * disruptor 通知核心
     */
    private Disruptor<E> disruptor = null;

    private EventTranslatorVararg<E> transactionLogEventTranslator ;

    /**
     * 初始化Disruptor
     * @return
     */
    private Disruptor<E> initDisruptor(){
        //创建工厂
        EventFactory<E> factory = null;
        Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        try {
            transactionLogEventTranslator = entityClass.newInstance();
        } catch (InstantiationException e) {
            log.error("Disruptor获取事件转换器出错",e);
        } catch (IllegalAccessException e) {
            log.error("Disruptor获取事件转换器出错",e);
        }

        Class<F> fClass = (Class<F>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        try {
            factory = fClass.newInstance();
        } catch (InstantiationException e) {
            log.error("Disruptor获取事件工厂出错",e);
        } catch (IllegalAccessException e) {
            log.error("Disruptor获取事件工厂出错",e);
        }
        //创建bufferSize ,也就是RingBuffer大小，必须是2的N次方(能将求模运算转为位运算提高效率 ), 否则影响性能
        int ringBufferSize = 1024 * 1024; //

        /**
         //BlockingWaitStrategy 是最低效的策略，但其对CPU的消耗最小并且在各种不同部署环境中能提供更加一致的性能表现
         WaitStrategy BLOCKING_WAIT = new BlockingWaitStrategy();
         //SleepingWaitStrategy 的性能表现跟BlockingWaitStrategy差不多，对CPU的消耗也类似，但其对生产者线程的影响最小，适合用于异步日志类似的场景
         WaitStrategy SLEEPING_WAIT = new SleepingWaitStrategy();
         //YieldingWaitStrategy 的性能是最好的，适合用于低延迟的系统。在要求极高性能且事件处理线数小于CPU逻辑核心数的场景中，推荐使用此策略；例如，CPU开启超线程的特性
         WaitStrategy YIELDING_WAIT = new YieldingWaitStrategy();
         */

        //创建disruptor, 泛型参数:传递的事件的类型
        // 第一个参数: 产生Event的工厂类, Event封装生成-消费的数据
        // 第二个参数: RingBuffer的缓冲区大小
        // 第三个参数: 线程池
        // 第四个参数: SINGLE单个生产者, MULTI多个生产者
        // 第五个参数: WaitStrategy 当消费者阻塞在SequenceBarrier上, 消费者如何等待的策略
        Disruptor<E> disruptor =
                new Disruptor<E>(factory, ringBufferSize, Executors.defaultThreadFactory(), ProducerType.SINGLE, new YieldingWaitStrategy());

        // Connect the handler，绑定消费者事件，可以是多个
        disruptor.handleEventsWith(eventHandlers);
        // Start the Disruptor, starts all threads running，启动Disruptor，启动所有线程，主要是消费者对应的EventProcessor侦听线程，消费者事件处理器开始侦听RingBuffer中的消息
        disruptor.start();
        return disruptor;
    }

    private synchronized Disruptor<E> getDisruptor(){
        if(disruptor == null){
            disruptor = initDisruptor();
        }
        return disruptor;
    }

    public void execute(A... a) {
        //Disruptor 的事件发布过程是一个两阶段提交的过程：
        //发布事件
        //1.配置并获得Disruptor,2.将数据装入RingBuffer
        RingBuffer<E> ringBuffer = getDisruptor().getRingBuffer();
        //发送数据
        try {
            //生产者向RingBuffer中写入消息
            ringBuffer.publishEvent(transactionLogEventTranslator,a);
        }catch (Exception e){
            log.error("Disruptor发送事件失败",e);
        }
    }
}
